﻿using System;
using System.Collections.Generic;
using System.Transactions;
using HelpersDotNet.DomainDrivenDesign.Infrastructure.DomainBase;
using HelpersDotNet.DomainDrivenDesign.Infrastructure.RepositoryFramework;
using HelpersDotNet.DomainDrivenDesign.Infrastructure.Transactions;
namespace HelpersDotNet.DomainDrivenDesign.Infrastructure
{
    public class UnitOfWork : IUnitOfWork
    {
        private Guid _key;
        private IClientTransactionRepository _clientTransactionRepository;
        private Dictionary<IEntity, IUnitOfWorkRepository> _addedEntities;
        private Dictionary<IEntity, IUnitOfWorkRepository> _deletedEntities;
        private Dictionary<IEntity, IUnitOfWorkRepository> _changedEntities;

        public UnitOfWork()
        {
            _key = Guid.NewGuid();
            _clientTransactionRepository = ClientTransactionRepositoryFactory.GetTransactionRepository();
            _addedEntities = new Dictionary<IEntity, IUnitOfWorkRepository>();
            _deletedEntities = new Dictionary<IEntity, IUnitOfWorkRepository>();
            _changedEntities = new Dictionary<IEntity, IUnitOfWorkRepository>();
        }

        #region IUnitOfWork Members

        public void RegisterAdded(IEntity entity, IUnitOfWorkRepository repository)
        {
            _addedEntities.Add(entity, repository);
        }

        public void RegisterDeleted(IEntity entity, IUnitOfWorkRepository repository)
        {
            _deletedEntities.Add(entity, repository);
        }

        public void RegisterUpdated(IEntity entity, IUnitOfWorkRepository repository)
        {
            _changedEntities.Add(entity, repository);
        }

        public void Commit()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                foreach (IEntity entity in _deletedEntities.Keys)
                {
                    _deletedEntities[entity].PersistDeletedItem(entity);
                    _clientTransactionRepository.Add(
                        new ClientTransaction(_key, TransactionType.Delete, entity));
                }

                foreach (IEntity entity in _addedEntities.Keys)
                {
                    _addedEntities[entity].PersistNewItem(entity);
                    _clientTransactionRepository.Add(
                        new ClientTransaction(_key, TransactionType.Insert, entity));
                }

                foreach (IEntity entity in _changedEntities.Keys)
                {
                    _changedEntities[entity].PersistUpdatedItem(entity);
                    _clientTransactionRepository.Add(
                        new ClientTransaction(_key, TransactionType.Update, entity));
                }
                scope.Complete();
            }

            _deletedEntities.Clear();
            _addedEntities.Clear();
            _changedEntities.Clear();
            _key = new Guid();
        }

        public object Key
        {
            get { return _key; }
        }

        public IClientTransactionRepository ClientTransactionRepository
        {
            get { return _clientTransactionRepository; }
        }

        #endregion
    }
}
